/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package CircuitTable;

import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.text.DecimalFormat;
import javax.swing.JPanel;

/**
 *
 * @author Libra
 */
public class PatternCanvas extends JPanel {

    private Graphics2D g2d;
    Font idFont, dataFont;
    private int[] connType = {0, 0, 0, 0, 0, 0};
    private int pattID = 0;
    private double pLess = 0;
    private double pMore = 1;
    private double act = 80;
    private double sim = 167.454;

    @Override
    public boolean isOpaque() {
        return true;
    }

    @Override
    protected void paintComponent(Graphics g) {
//        System.out.println("painted");
        g2d = (Graphics2D) g;
        setDefaultPara();

        drawBG();
        drawPattern();
        drawID();
        drawRatio();
        drawRatioFig();
        drawP();

    }

    private void setDefaultPara() {
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        g2d.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
        dataFont = new Font("Serif", Font.PLAIN, 20);
        idFont = new Font("Serif", Font.PLAIN, 28);
    }

    private void drawBG() {
        if (pLess < 0.05) {
            g2d.setColor(Color.LIGHT_GRAY);
        } else if (pMore < 0.05) {
            g2d.setColor(Color.PINK);
        } else {
            g2d.setColor(Color.WHITE);
        }
        g2d.fillRect(0, 0, 320, 320);
    }

    private void drawPattern() {

        Point2D.Double c1 = new Point2D.Double(140, 60);
        Point2D.Double c2 = new Point2D.Double(40, 220);
        Point2D.Double c3 = new Point2D.Double(240, 220);

        double dd = 30;
        double rr=dd/2;

        g2d.setColor(Color.BLACK);
        g2d.draw(new Ellipse2D.Double(c1.getX()-rr, c1.getY()-rr, dd, dd));
        g2d.draw(new Ellipse2D.Double(c2.getX()-rr, c2.getY()-rr, dd, dd));
        g2d.draw(new Ellipse2D.Double(c3.getX()-rr, c3.getY()-rr, dd, dd));

        drawArrow(c2, c1, connType[0]);
        drawArrow(c1, c2, connType[1]);
        drawArrow(c1, c3, connType[2]);
        drawArrow(c3, c1, connType[3]);
        drawArrow(c3, c2, connType[4]);
        drawArrow(c2, c3, connType[5]);
    }

    private void drawID() {
        g2d.setColor(Color.BLACK);
        g2d.setFont(idFont);

        g2d.drawString("ID:" + Integer.toString(pattID), 20, 30);

    }

    private void drawRatio() {
        g2d.setColor(Color.BLACK);
        g2d.setFont(dataFont);

        g2d.drawString("Act " + Double.toString(act), 20, 270);
        g2d.drawString("Sim " + Double.toString(sim), 20, 290);

        DecimalFormat df = new DecimalFormat("#.####");
        g2d.drawString("Act:Sim " + df.format(act / sim), 20, 310);
    }

    private void drawRatioFig() {
        double xx = 280;
        double yTop = 100;
        double yBot = 220;
        float width = 15;
        double yMid;
        Point2D.Double topPt = new Point2D.Double(xx, yTop);
        Point2D.Double botPt = new Point2D.Double(xx, yBot);
        Point2D.Double midPt;

        g2d.setStroke(new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));

        if (act > sim) {
            yMid = yBot - (yBot - yTop) * (sim / act);
            midPt = new Point2D.Double(xx, yMid);
            drawFigPart(botPt, midPt, Color.GREEN);
            drawFigPart(midPt, topPt, Color.BLUE);
        } else {
            yMid = yBot - (yBot - yTop) * (act / sim);
            midPt = new Point2D.Double(xx, yMid);
            drawFigPart(botPt, midPt, Color.BLUE);
            drawFigPart(midPt, topPt, Color.GREEN);
        }
    }

    private void drawFigPart(Point2D.Double fromPt, Point2D.Double toPt, Color c) {
        g2d.setColor(c);
        g2d.draw(new Line2D.Double(fromPt, toPt));
    }

    private void drawP() {
        g2d.setColor(Color.BLACK);
        g2d.setFont(dataFont);

        g2d.drawString(significance(pLess) + "pLess " + Double.toString(pLess), 160, 20);
        g2d.drawString(significance(pMore) + "pMore " + Double.toString(pMore), 160, 40);
    }

    private String significance(double d) {
        if (d < 0.005) {
            return "*** ";
        } else if (d < 0.01) {
            return " ** ";
        } else if (d < 0.05) {
            return "  * ";
        } else {
            return "    ";
        }
    }

    private Point2D.Double biasPt(Point2D.Double fromPt, Point2D.Double toPt, boolean returnFrom) {
        double crossD = 10;
        double trim = 40;

        double lineRad = Math.atan2(fromPt.getY() - toPt.getY(), fromPt.getX() - toPt.getX());

        double trimX = trim * Math.cos(lineRad);
        double trimY = trim * Math.sin(lineRad);

        double biasX = crossD * Math.sin(lineRad);
        double biasY = crossD * Math.cos(lineRad);

        Point2D.Double newFromPt, newToPt;

        newFromPt = new Point2D.Double(fromPt.getX() - biasX - trimX, fromPt.getY() + biasY - trimY);
        newToPt = new Point2D.Double(toPt.getX() - biasX + trimX, toPt.getY() + biasY + trimY);

        return returnFrom ? newFromPt : newToPt;
    }

    private void drawArrow(Point2D.Double fromPt, Point2D.Double toPt, int type) {
        Point2D.Double transX = biasPt(fromPt, toPt, true);
        Point2D.Double transY = biasPt(fromPt, toPt, false);

        switch (type) {
            case 0:
                break;
            case 1:
                g2d.setColor(Color.RED);
                g2d.draw(new Line2D.Double(transX, transY));
                drawArrowHead(transX, transY);
                break;
            case 2:
                g2d.setColor(Color.GREEN);
                g2d.draw(new Line2D.Double(transX, transY));
                drawArrowHead(transX, transY);
                break;
        }
    }

    private void drawArrowHead(Point2D fromPt, Point2D toPt) {

        double arrowLength = 30;
        double arrowDeg = 20;

        double arrowRad = arrowDeg / 180 * 3.14;
        Point2D.Double cwP, ccwP;
        double lineDeg, cwDeg, ccwDeg;

        lineDeg = Math.atan2(fromPt.getY() - toPt.getY(), fromPt.getX() - toPt.getX());
        cwDeg = lineDeg + arrowRad;
        ccwDeg = lineDeg - arrowRad;

        cwP = new Point2D.Double(toPt.getX() + arrowLength * Math.cos(cwDeg),
                toPt.getY() + arrowLength * Math.sin(cwDeg));
        ccwP = new Point2D.Double(toPt.getX() + arrowLength * Math.cos(ccwDeg),
                toPt.getY() + arrowLength * Math.sin(ccwDeg));

        g2d.draw(new Line2D.Double(toPt, cwP));
        g2d.draw(new Line2D.Double(toPt, ccwP));

    }
//
//    public PatternCanvas() {
//        connType = new int[6];
//        Arrays.fill(connType, 0);
//        repaint();
//    }

    public void refresh() {
        repaint();
    }

    public void setConnType(int[] types) {
        connType = types;
    }

    public void setPattID(int pid) {
        pattID = pid;
    }

    public void setSim(double s) {
        sim = s;
    }

    public void setAct(double a) {
        act = a;
    }

    public void setPLess(double pl) {
        pLess = pl;
    }

    public void setPMore(double pm) {
        pMore = pm;
    }
}
